package com.wxxymaker.service.impl;

import com.wxxymaker.model.dao.MarkRecordDao;
import com.wxxymaker.model.dao.StageDao;
import com.wxxymaker.model.dao.UserDao;
import com.wxxymaker.model.entity.MarkRecord;
import com.wxxymaker.model.entity.Shop;
import com.wxxymaker.model.entity.Stage;
import com.wxxymaker.model.entity.User;
import com.wxxymaker.service.MarkRecordService;
import com.wxxymaker.service.StageService;
import com.wxxymaker.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;

/**
 * @Author: Soft
 * @Date: 2018/5/5 21:12
 * @Desc: 打分记录业务层实现
 */
@Service
public class MarkRecordServiceImpl implements MarkRecordService {

    private final MarkRecordDao dao;

    private final MarkRecordDao markRecordDao;

    private final StageDao stageDao;

    private final UserDao userDao;

    @Autowired
    public MarkRecordServiceImpl(MarkRecordDao dao, MarkRecordDao markRecordDao, StageDao stageDao, UserDao userDao) {
        this.dao = dao;
        this.markRecordDao = markRecordDao;
        this.stageDao = stageDao;
        this.userDao = userDao;
    }

    @Override
    @Transactional
    public MarkRecord add(MarkRecord markRecord) {
        if (markRecordDao.countByUserAndStage(markRecord.getUser(), markRecord.getStage()) == 0) { // 打分计数 只会记录一次
            stageDao.addUserSum(markRecord.getStage().getId());
            userDao.addNum(markRecord.getUser().getId());
        }

        markRecord.setTime(new Date());
        return dao.save(markRecord);
    }

    @Override
    @Transactional
    public MarkRecord delete(Integer id) {
        MarkRecord markRecord = dao.findOne(id.longValue());
        if (null != markRecord) {
            dao.delete(id.longValue());
        }
        return markRecord;
    }

    @Override
    @Transactional
    public boolean change(MarkRecord markRecord) {
        return 0 < markRecord.getId() && null != dao.saveAndFlush(markRecord);
    }

    @Override
    public MarkRecord getOne(Integer id) {
        return dao.findOne(id.longValue());
    }

    @Override
    public Page<MarkRecord> page(Map<String, Object> map, Integer pageNo, Integer size) {
        Specification<MarkRecord> specification = new Specification<MarkRecord>() {
            @Override
            public Predicate toPredicate(Root<MarkRecord> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                if (map == null)
                    return null;
                List<Predicate> ps = new LinkedList<>();
                map.forEach((key, val)->{
                    if ((val instanceof String && !"".equals(val)) ||
                            (val instanceof Integer && (Integer) val > 0)) {// 过滤掉空表单参数
                        switch (key) {
                            case "stage_id":
                                ps.add(builder.equal(root.get("stage").get("id"), val));
                                break;
                            case "shop_id":
                                ps.add(builder.equal(root.get("shop").get("id"), val));
                                break;
                            case "user_id":
                                ps.add(builder.equal(root.get("user").get("id"), val));
                                break;
                            default:
                                ps.add(builder.equal(root.get(key), val));
                                break;
                        }
                        // 新增用来根据用户名搜索
                    } else if (val instanceof Collection) {
                        if ("user_ids".equals(key)) {
                            ps.add(root.get("user").get("id").in(((Collection) val).toArray()));
                        }
                    }
                });
                query.where(ps.toArray(new Predicate[ps.size()]));
                return null;
            }
        };
        if (pageNo < 1) {
            pageNo = 1;
        }
        Pageable pageable = new PageRequest(pageNo - 1, size,
                new Sort(Sort.Direction.DESC, "time"));
        return dao.findAll(specification, pageable);
    }

    @Override
    public Page<MarkRecord> page(Map<String, Object> map, Integer pageNo) {
        return this.page(map, pageNo, 12);
    }

    @Override
    public Page<MarkRecord> page(Integer pageNo) {
        return this.page(null, pageNo, 12);
    }

    @Override
    public boolean isHas(User user, Shop shop, Stage stage) {
        MarkRecord markRecord = dao.findByUserAndShopAndStage(user, shop, stage);
        return markRecord != null;
    }

    @Override
    public boolean isHas(User user, Stage stage) {
        return dao.countByUserAndStage(user, stage) > 0;
    }

    @Override
    public boolean isHas(int uid, int sid) {
        return dao.countByUserIdAndStageId(uid, sid) > 0;
    }

    @Override
    public long countForStar(Stage stage, Shop shop, Integer star) {
        return dao.countByStageAndShopAndStar(stage, shop, star);
    }

    @Override
    public long getUserNum(Stage stage) {
        return dao.countDistinctByStage(stage);
    }
}
